package com.john.springsecuritydemo.config;

import com.john.springsecuritydemo.handle.MyAccessDeniedHandler;
import com.john.springsecuritydemo.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * SpringSecurity配置类
 * 日期 2021/6/2 19:16
 * 创建者：john driver
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    @Bean
    PersistentTokenRepository getPersistentTokenRepository(){
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //自动建表，第二次启动要注释掉
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
    // 密码加密器
    @Bean
    public PasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }
    // 自定义登录页面
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                //当发现/login时认为是登录，必须与表单提交的地址一样，就可以去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功跳转页面，Post请求
                .successForwardUrl("/toMain")
                //.successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
                //登录失败后跳转页面，post请求
                .failureForwardUrl("/toError")
                //.failureHandler(new MyAuthenticationFailureHandler("/error.html"))
                //自定义表单传过来的用户名和密码的name
                .usernameParameter("username123")
                .passwordParameter("password123")
        ;
        //认证授权
        http.authorizeRequests()
                //login.html error.html不需要认证
                .antMatchers("/error.html").permitAll()
                //.antMatchers("/error.html").access("permitAll")
                .antMatchers("/login.html").permitAll()
                //放行静态资源
                .antMatchers("/js/**","/css/**","/images/**").permitAll()
                .antMatchers("/**/*.jpg").permitAll()
                .antMatchers(HttpMethod.GET,"/**/*.jpg").permitAll()
                //正则方式
                .regexMatchers(".+[.]jpg").permitAll()
                //mvcMatchers
                .mvcMatchers("/demo").servletPath("/xxx").permitAll()
                .antMatchers("/main1.html").rememberMe()
                .antMatchers("/showLogin").permitAll()
                //任何请求,都需要认证，必须登录后才可以访问
                .anyRequest().authenticated()
                // .anyRequest().access("@myServiceImpl.hasPermission(request,authentication)")
        ;
        //关闭csrf防护
        //http.csrf().disable();

        http.exceptionHandling()
                .accessDeniedHandler(myAccessDeniedHandler)
        ;

        http.rememberMe()
                //过期时间（默认两周）
                .tokenValiditySeconds(60)
                //.rememberMeParameter() //表单参数 默认remember-me
                //DetailsService登录逻辑
                .userDetailsService(userDetailsService)
                //存储token的Repository
                .tokenRepository(persistentTokenRepository)
        ;

        http.logout()
                //前端提交退出的url（默认/logout）
                .logoutUrl("/logout")
                //退出登录跳转页面
                .logoutSuccessUrl("/login.html")
        ;
    }
}
